import { createSelector } from '@reduxjs/toolkit';
import { stateSelector } from 'app/store/store';
import { useAppSelector } from 'app/store/storeHooks';
import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
import { isInvocationNode } from 'features/nodes/types/types';
import { activeTabNameSelector } from 'features/ui/store/uiSelectors';
import { forEach, map } from 'lodash-es';
import { getConnectedEdges } from 'reactflow';

const selector = createSelector(
  [stateSelector, activeTabNameSelector],
  (state, activeTabName) => {
    const { generation, system, nodes } = state;
    const { initialImage, model } = generation;

    const { isProcessing, isConnected } = system;

    const reasons: string[] = [];

    // Cannot generate if already processing an image
    if (isProcessing) {
      reasons.push('系统繁忙，请稍等');
    }

    // Cannot generate if not connected
    if (!isConnected) {
      reasons.push('服务未连接');
    }

    if (activeTabName === 'img2img' && !initialImage) {
      reasons.push('未添加参考图');
    }

    if (activeTabName === 'nodes' && nodes.shouldValidateGraph) {
      if (!nodes.nodes.length) {
        reasons.push('No nodes in graph');
      }

      nodes.nodes.forEach((node) => {
        if (!isInvocationNode(node)) {
          return;
        }

        const nodeTemplate = nodes.nodeTemplates[node.data.type];

        if (!nodeTemplate) {
          // Node type not found
          reasons.push('Missing node template');
          return;
        }

        const connectedEdges = getConnectedEdges([node], nodes.edges);

        forEach(node.data.inputs, (field) => {
          const fieldTemplate = nodeTemplate.inputs[field.name];
          const hasConnection = connectedEdges.some(
            (edge) =>
              edge.target === node.id && edge.targetHandle === field.name
          );

          if (!fieldTemplate) {
            reasons.push('Missing field template');
            return;
          }

          if (fieldTemplate.required && !field.value && !hasConnection) {
            reasons.push(
              `${node.data.label || nodeTemplate.title} -> ${
                field.label || fieldTemplate.title
              } missing input`
            );
            return;
          }
        });
      });
    } else {
      if (!model) {
        reasons.push('未选择模型');
      }

      if (state.controlNet.isEnabled) {
        map(state.controlNet.controlNets).forEach((controlNet, i) => {
          if (!controlNet.isEnabled) {
            return;
          }
          if (!controlNet.model) {
            reasons.push(`控制器 ${i + 1} 未选择模型`);
          }

          if (
            !controlNet.controlImage ||
            (!controlNet.processedControlImage &&
              controlNet.processorType !== 'none')
          ) {
            reasons.push(`控制器 ${i + 1} 未添加参考图`);
          }
        });
      }
    }

    return { isReady: !reasons.length, isProcessing, reasons };
  },
  defaultSelectorOptions
);

export const useIsReadyToInvoke = () => {
  const { isReady, isProcessing, reasons } = useAppSelector(selector);
  return { isReady, isProcessing, reasons };
};
